1. Field of the Invention
The invention relates generally to a power-saving technique in a digital circuit and, more particularly, to a power-saving technique in a synchronous digital core design having multiple clock domains.
2. Description of the Related Art
Many modern synchronous circuits or system designs implement a mode called a “sleep mode,” which is a power-saving mode that the designs enter when they are essentially idle. Sleep mode is becoming increasingly common in “System On a Chip” (SOC) designs. SOCs are so named because they typically have one or more processors, one or more memory interfaces, and interfaces to various Input/Output (I/O) busses all on the same chip. SOCs are usually created out of “core” designs that are “stitched” together to make the SOC. For example, an SOC may have a plurality of cores such as a processor core, a memory core, an Ethernet core, a PCI core, serial port core, etc. Due to the large amount of functions on the single chip, power conservation is important. Also, because there are many different functions on a single chip, much of the time one or more of the individual core functions will be idle.
When a core is “idle” and is therefore not processing any transactions, many of that core's latches are still consuming power because they are still being clocked. Some of these latches may feed downstream combinational logic causing those combinational gates to switch and also consume power needlessly. The solution has been for the core to go into sleep mode when it has been idle for some programmable amount of time. While a core is in sleep mode, the clocks to all or most of its latches are gated off so that the core consumes almost no power. A core may decide on its own to enter sleep mode, but typically it makes a request to the SOC to go to sleep via a signal called SLEEP_REQ. If the SOC supports sleep mode and that mode is enabled for the particular core, the system will return a SLEEP_ACK signal to the core. The SLEEP_ACK signal (or sometimes a negative active SLEEP_N signal) has traditionally been used by the core to directly gate the clocks inside the core. If the SOC never activates the SLEEP_ACK signal in response to a SLEEP_REQ, then the core will not enter sleep mode. Because there is often a performance penalty for “waking up” from sleep mode, cores typically have programmable counters that make them wait to assert SLEEP_REQ only if they have been idle for some reasonable programmable time.
Once a core is in sleep mode, it will “wake up” when it determines that it is no longer idle. The conditions that cause a core to wake up are specific to each design but they are typically things like a bus transaction whose destination is that core, or an interrupt arriving, etc. When the core detects a wake up event, it will deassert SLEEP_REQ and the SOC will in turn deassert SLEEP_ACK. The clocks will start running again and the core can process the wake up event. While in sleep mode, the core design must take care not to gate the clocks of any part of the design that needs to detect wake-up conditions or any part of the design that must respond to stimulus while the core is in sleep mode. For example, a decode logic cannot typically be gated. Also, the core may have to be able to retry transactions that are destined for it while it is asserting the SLEEP_REQ signal and after it deasserts the SLEEP_REQ signal but before the SLEEP_ACK signal deactivates taking it out of sleep mode.
Cores with single clock domains can switch in and out of sleep mode without difficulty. Implementing sleep mode becomes more complex when a core has multiple clock domains. In this case, the process must be carefully controlled so that going to sleep mode is a process that must complete in all clock domains before the wake-up process can begin. One of the clock domains in a multiple clock domain core is the one that is asserting the SLEEP_REQ to the SOC and is receiving the SLEEP_ACK signal back. This clock domain is called a primary clock domain, whereas the other clock domain(s) are called secondary clock domains. There are several different architectures where implementing sleep mode becomes problematic.
There is a first case where only the primary clock domain receives a wake-up event, i.e., there are no wake-up events that can come from secondary clock domain(s). This first case, for example, includes a one-way I/O core such as a PCI, which takes transactions from a local bus running off of a local clock and runs those transactions on the PCI bus using a PCI clock. In this example, the local bus is in the primary clock domain, whereas the PCI bus is in the secondary clock domain. The primary clock domain decides when to sleep and when to wake up.
The first problem faced is that the SLEEP_ACK signal is a primary clock domain signal and must be synchronized to the secondary domains before being able to be used there. But just synchronizing the SLEEP_ACK signal to the secondary domains and using the synchronized versions to gate the clocks in those domains creates many race conditions and problems. When SLEEP_ACK is deasserted in the primary clock domain, it may still be asserted in one or more secondary clock domains. Thus, the primary clock domain cannot look only at its own SLEEP_ACK to know when it can safely communicate with the secondary clock domains.
At first glance, the simple solution to this problem is to feed the synchronized SLEEP_ACK back from the secondary clock domains (synchronized again) to the primary clock domain so that the primary clock domain can “see” when the secondary clock domains are really awake. So when the primary clock domain sees its own SLEEP_ACK deasserted, it simply waits until all of the other domains also have an inactive SLEEP_ACK. However, there are race conditions that cause this solution not to work. If the SLEEP_REQ is permitted to assert for a brief period of time (e.g., a small number of primary clocks) and then quickly deassert due to a wake-up event, the SLEEP_ACK signal could be asserted for a short period of time.
This is problematic when it is sent to other clock domains. The primary clock domain may see its own SLEEP_ACK assert and then deassert before the synchronized versions of the secondary SLEEP_ACK signals have gotten a chance to ever assert in the primary domain. This way, the primary domain will see those domains as being awake just because the SLEEP_ACK pulse has not gotten through the synchronization logic and back yet. This may cause the primary clock domain to start talking to a secondary clock domain just as it is briefly going to sleep. Some SLEEP_ACK pulses may be so short in the primary clock domain that they do not even show up in a secondary domain. Even if they do show up, their synchronized version back to the primary clock domain may not show up. This fact prevents the primary clock domain from even waiting for the secondary clock domains to assert and then deassert their synchronized version of SLEEP_ACK signals.
Furthermore, there are more difficult and general situations where there are not only multiple clock domains but idle and wake-up events can happen from more than one clock domain. A two clock domain example of this situation could be a PCI bridge that forwards transactions in two directions: (1) from the local bus to PCI and (2) from PCI to the local bus. Each side of the bridge operates on a different clock. When such a bridge core is in a sleep mode, a transaction arriving from either side of the bridge should cause the core to wake up.
Making this scenario work is not straightforward due to the race conditions discussed above as well as other race conditions that arise due to the fact that both sides can now initiate wake-up events. An example of one of these other race conditions is as follows: Assume that the local side is the primary clock domain, which means that SLEEP_REQ is asserted in that domain and that SLEEP_ACK is received in that domain. In this case, the primary clock domain can decide to assert SLEEP_REQ because it believes that the primary and secondary clock domains have both been idle for some time. But any information that the primary clock domain has about the secondary clock domain is delayed due to the synchronization interface. Therefore, the secondary clock domain may actually have gone non-idle due to a transaction arriving around the time that the primary clock domain asserts SLEEP_REQ. This will cause the SLEEP_ACK signal to arrive and put the core to sleep right in the middle of processing a transaction. There are other race conditions involved in waking up. If the secondary clock domain detects a transaction destined for the core, it will wake up and deassert its IDLE signal. That IDLE signal will cross the synchronization logic and eventually cause the core to deassert SLEEP_REQ and SLEEP_ACK will deassert. The secondary clock domain cannot start talking to the primary clock domain as soon as it deasserts its idle signal. Likewise, the primary clock domain cannot start talking to the secondary clock domain as soon as it sees SLEEP_ACK deassert. All of these race conditions occur because different clock domains are making decisions based on information, some of which is current and some of which is not current due to the synchronization delay.
Therefore, a need exists for implementing a power-saving sleep mode in a synchronous design having multiple clock domains without the aforementioned problems including various race conditions.